//
//  BehaviorSubjectTest.swift
//  RxTests
//
//  Created by Krunoslav Zaher on 5/23/15.
//
//

import Foundation
import XCTest
import RxSwift

class BehaviorSubjectTest : RxTest {
    
    func test_Infinite() {
        let scheduler = TestScheduler(initialClock: 0);
        
        let xs = scheduler.createHotObservable([
            next(70, 1),
            next(110, 2),
            next(220, 3),
            next(270, 4),
            next(340, 5),
            next(410, 6),
            next(520, 7),
            next(630, 8),
            next(710, 9),
            next(870, 10),
            next(940, 11),
            next(1020, 12)
        ])
        
        var subject: BehaviorSubject<Int>! = nil
        var subscription: Disposable! = nil
        
        let results1: MockObserver<Int> = scheduler.createObserver()
        var subscription1: Disposable! = nil
        
        let results2: MockObserver<Int> = scheduler.createObserver()
        var subscription2: Disposable! = nil
        
        let results3: MockObserver<Int> = scheduler.createObserver()
        var subscription3: Disposable! = nil
        
        scheduler.scheduleAt(100) { subject = BehaviorSubject<Int>(value: 100) }
        scheduler.scheduleAt(200) { subscription = xs.subscribe(subject) }
        scheduler.scheduleAt(1000) { subscription.dispose() }
        
        scheduler.scheduleAt(300) { subscription1 = subject.subscribe(results1) }
        scheduler.scheduleAt(400) { subscription2 = subject.subscribe(results2) }
        scheduler.scheduleAt(900) { subscription3 = subject.subscribe(results3) }
        
        scheduler.scheduleAt(600) { subscription1.dispose() }
        scheduler.scheduleAt(700) { subscription2.dispose() }
        scheduler.scheduleAt(800) { subscription1.dispose() }
        scheduler.scheduleAt(950) { subscription3.dispose() }
        
        scheduler.start()
        
        XCTAssertEqual(results1.messages, [
            next(300, 4),
            next(340, 5),
            next(410, 6),
            next(520, 7)
        ])
        
        XCTAssertEqual(results2.messages, [
            next(400, 5),
            next(410, 6),
            next(520, 7),
            next(630, 8)
        ])
        
        XCTAssertEqual(results3.messages, [
            next(900, 10),
            next(940, 11)
        ])
    }
    
    func test_Finite() {
        let scheduler = TestScheduler(initialClock: 0);
        
        let xs = scheduler.createHotObservable([
            next(70, 1),
            next(110, 2),
            next(220, 3),
            next(270, 4),
            next(340, 5),
            next(410, 6),
            next(520, 7),
            completed(630),
            next(640, 9),
            completed(650),
            error(660, testError)
        ])
        
        var subject: BehaviorSubject<Int>! = nil
        var subscription: Disposable! = nil
        
        let results1: MockObserver<Int> = scheduler.createObserver()
        var subscription1: Disposable! = nil
        
        let results2: MockObserver<Int> = scheduler.createObserver()
        var subscription2: Disposable! = nil
        
        let results3: MockObserver<Int> = scheduler.createObserver()
        var subscription3: Disposable! = nil
        
        scheduler.scheduleAt(100) { subject = BehaviorSubject<Int>(value: 100) }
        scheduler.scheduleAt(200) { subscription = xs.subscribe(subject) }
        scheduler.scheduleAt(1000) { subscription.dispose() }
        
        scheduler.scheduleAt(300) { subscription1 = subject.subscribe(results1) }
        scheduler.scheduleAt(400) { subscription2 = subject.subscribe(results2) }
        scheduler.scheduleAt(900) { subscription3 = subject.subscribe(results3) }
        
        scheduler.scheduleAt(600) { subscription1.dispose() }
        scheduler.scheduleAt(700) { subscription2.dispose() }
        scheduler.scheduleAt(800) { subscription1.dispose() }
        scheduler.scheduleAt(950) { subscription3.dispose() }
        
        scheduler.start()
        
        XCTAssertEqual(results1.messages, [
            next(300, 4),
            next(340, 5),
            next(410, 6),
            next(520, 7)
            ])
        
        XCTAssertEqual(results2.messages, [
            next(400, 5),
            next(410, 6),
            next(520, 7),
            completed(630)
            ])
        
        XCTAssertEqual(results3.messages, [
            completed(900)
            ])
    }
    
    func test_Error() {
        let scheduler = TestScheduler(initialClock: 0);

        let xs = scheduler.createHotObservable([
            next(70, 1),
            next(110, 2),
            next(220, 3),
            next(270, 4),
            next(340, 5),
            next(410, 6),
            next(520, 7),
            error(630, testError),
            next(640, 9),
            completed(650),
            error(660, testError)
            ])
        
        var subject: BehaviorSubject<Int>! = nil
        var subscription: Disposable! = nil
        
        let results1: MockObserver<Int> = scheduler.createObserver()
        var subscription1: Disposable! = nil
        
        let results2: MockObserver<Int> = scheduler.createObserver()
        var subscription2: Disposable! = nil
        
        let results3: MockObserver<Int> = scheduler.createObserver()
        var subscription3: Disposable! = nil
        
        scheduler.scheduleAt(100) { subject = BehaviorSubject<Int>(value: 100) }
        scheduler.scheduleAt(200) { subscription = xs.subscribe(subject) }
        scheduler.scheduleAt(1000) { subscription.dispose() }
        
        scheduler.scheduleAt(300) { subscription1 = subject.subscribe(results1) }
        scheduler.scheduleAt(400) { subscription2 = subject.subscribe(results2) }
        scheduler.scheduleAt(900) { subscription3 = subject.subscribe(results3) }
        
        scheduler.scheduleAt(600) { subscription1.dispose() }
        scheduler.scheduleAt(700) { subscription2.dispose() }
        scheduler.scheduleAt(800) { subscription1.dispose() }
        scheduler.scheduleAt(950) { subscription3.dispose() }
        
        scheduler.start()
        
        XCTAssertEqual(results1.messages, [
            next(300, 4),
            next(340, 5),
            next(410, 6),
            next(520, 7)
            ])
        
        XCTAssertEqual(results2.messages, [
            next(400, 5),
            next(410, 6),
            next(520, 7),
            error(630, testError)
            ])
        
        XCTAssertEqual(results3.messages, [
            error(900, testError)
            ])
    }
    
    func test_Canceled() {
        let scheduler = TestScheduler(initialClock: 0);
        
        let xs = scheduler.createHotObservable([
            completed(630),
            next(640, 9),
            completed(650),
            error(660, testError)
            ])
        
        var subject: BehaviorSubject<Int>! = nil
        var subscription: Disposable! = nil
        
        let results1: MockObserver<Int> = scheduler.createObserver()
        var subscription1: Disposable! = nil
        
        let results2: MockObserver<Int> = scheduler.createObserver()
        var subscription2: Disposable! = nil
        
        let results3: MockObserver<Int> = scheduler.createObserver()
        var subscription3: Disposable! = nil
        
        scheduler.scheduleAt(100) { subject = BehaviorSubject<Int>(value: 100) }
        scheduler.scheduleAt(200) { subscription = xs.subscribe(subject) }
        scheduler.scheduleAt(1000) { subscription.dispose() }
        
        scheduler.scheduleAt(300) { subscription1 = subject.subscribe(results1) }
        scheduler.scheduleAt(400) { subscription2 = subject.subscribe(results2) }
        scheduler.scheduleAt(900) { subscription3 = subject.subscribe(results3) }
        
        scheduler.scheduleAt(600) { subscription1.dispose() }
        scheduler.scheduleAt(700) { subscription2.dispose() }
        scheduler.scheduleAt(800) { subscription1.dispose() }
        scheduler.scheduleAt(950) { subscription3.dispose() }
        
        scheduler.start()
        
        XCTAssertEqual(results1.messages, [
            next(300, 100),
        ])
        
        XCTAssertEqual(results2.messages, [
            next(400, 100),
            completed(630)
        ])
        
        XCTAssertEqual(results3.messages, [
            completed(900)
        ])
    }
}